package com.seednia.foundation.framework.service;

import java.util.List;

import com.seednia.foundation.framework.dto.AbstractRecord;
import com.seednia.foundation.framework.dto.ICriteria;
import com.seednia.foundation.framework.dto.QueryParams;

/**
 * This interface defines common operations that all service that manages  
 * persistent records should implement.
 * 
 * @author Young-Suk
 * 
 */
public interface IDataOrientedService extends IService {

	/**
	 * Returns the record type 
	 * @return
	 */
	Class<? extends AbstractRecord> getRecordClass();

	/**
	 * Sets the record type that this DataOrientedService handles
	 * @param recordClass
	 */
	void setRecordClass(Class<? extends AbstractRecord> recordClass);
	
	/**
	 * Returns the criteria type 
	 * @return
	 */
	Class<?> getCriteriaClass();
	
	/**
	 * Factory function to crate a specific instance of record
	 * @return
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 */
	AbstractRecord createRecordInstance() throws InstantiationException, IllegalAccessException;

	/**
	 * Factory function to crate a specific instance of record
	 * @param record
	 * @return
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 */
	ICriteria createCriteriaInstance() ;

	/**
	 * Factory function to crate a specific instance of record
	 * @param record
	 * @return
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 */
	ICriteria createCriteriaInstance(AbstractRecord record) throws InstantiationException, IllegalAccessException;


	/**
	 * Returns true if the criteria creates unique result, false otherwiss.
	 * This operation can b use on get and delete methods to restrict scoping.
	 * @param criteria
	 * @return
	 */
	boolean returnsUnique(ICriteria criteria);
	
	/**
	 * Get a record from received criteria
	 * 
	 * @param criteria
	 * @return a record which properly match with the criteria
	 */
	AbstractRecord getRecord(RequestContext requestContext, ICriteria criteria)
			throws ServiceException;

	/**
	 * Get records from received criteria
	 * 
	 * @param criteria
	 * @return a list of records which properly match with the criteria
	 */
	List<AbstractRecord> listRecords(RequestContext requestContext, ICriteria criteria, QueryParams params)
			throws ServiceException;

	/**
	 * insert a record to database
	 * 
	 * @param record
	 *            added record
	 * @return a sequence number of added record
	 */
	 Long insertRecord(RequestContext requestContext, AbstractRecord record)
			throws ServiceException;

	/**
	 * remove a record from database
	 * 
	 * @param record
	 *            removed record
	 * @return a number of affected record
	 */
	 int deleteRecord(RequestContext requestContext, ICriteria criteria)
			throws ServiceException;

	/**
	 * update a record in database
	 * 
	 * @param record
	 *            updated record
	 * @return a number of affected record
	 */
	 int updateRecord(RequestContext requestContext, AbstractRecord record)
			throws ServiceException;
	

	/**
	 * Updates a record in database. This operation is used when the previous state
	 * of the object before update is required. E.g. Calculating the change in time.
	 * 
	 * @param oldRecord
	 *            previous record state
	 * @param newRecord
	 *            updated record
	 * @return a number of affected record
	 */
	 int updateRecord(RequestContext requestContext, AbstractRecord oldRecord, AbstractRecord newRecord)
			throws ServiceException;

	 
	 /**
	  * Checks that all the references are correct before inserting.
	  * First it retrieves the the reference record by unique key column other than the SID.
	  * Then set the retrieved DTO object to the reference.
	  * Finally it insert the record.
	  * 
	  * @param record
	  * @return
	  * @throws ServiceException
	  */
	 public Long prepareReferencesAndInsert(RequestContext requestContext, AbstractRecord record) 
	 	throws ServiceException;
}
